package pe.com.casadesign.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import pe.com.casadesign.dao.OrdenCompraDAO;
import pe.com.casadesign.domain.Cliente;
import pe.com.casadesign.domain.Guia;
import pe.com.casadesign.domain.Item;
import pe.com.casadesign.domain.LineaGuia;
import pe.com.casadesign.domain.LineaOrdenCompra;
import pe.com.casadesign.domain.ListaItem;
import pe.com.casadesign.domain.ListaLineaGuia;
import pe.com.casadesign.domain.ListaLineaOrdenCompra;
import pe.com.casadesign.domain.ListaOrdenCompra;
import pe.com.casadesign.domain.OrdenCompra;
import pe.com.casadesign.domain.Prestamo;
import pe.com.casadesign.domain.Producto;
import pe.com.casadesign.domain.Proveedor;
import pe.com.casadesign.domain.Solicitud;
import pe.com.casadesign.domain.Tienda;
import pe.com.casadesign.domain.Usuario;
import pe.com.casadesign.domain.Moneda;

/**
 * Implementacion de OrdenCompraDAO.
 * 
 * @author Pedro Vera
 * 
 */
@Repository
public class OrdenCompraDAOImpl implements OrdenCompraDAO {
	private static final Logger logger = LoggerFactory.getLogger(OrdenCompraDAOImpl.class);
	
	// Nombre Procedimientos Almacenados
	private static String SP_LISTAR_ORDENCOMPRA = "SP_LISTAR_ORDENCOMPRA";
	private static String SP_OBTENER_ORDENCOMPRA = "SP_OBTENER_ORDENCOMPRA";
	private static String SP_REGISTRAR_ORDENCOMPRA = "SP_REGISTRAR_ORDENCOMPRA";
	private static String SP_REGISTRAR_DET_ORDENCOMPRA = "SP_REGISTRAR_DET_ORDENCOMPRA";
	private static String SP_MODIFICAR_ORDENCOMPRA = "SP_MODIFICAR_ORDENCOMPRA";
	private static String SP_LIMPIAR_DET_ORDENCOMPRA = "SP_LIMPIAR_DET_ORDENCOMPRA";
		
	// Parametros de Entrada
	private static String PARAM_CODORDENCOMPRA = "p_codoc";
	private static String PARAM_LIMCODORDENCOMPRA = "p_codordencompra";
	private static String PARAM_PRECIOINTERNALFREIGHT = "p_precioif";
	private static String PARAM_CODMONEDA = "p_codMoneda";
	private static String PARAM_CODPROVEEDOR = "p_codproveedor";
	private static String PARAM_CODUSUARIO = "p_codusuario";
	private static String PARAM_ORIGEN = "p_origen";
	private static String PARAM_ESTADO = "p_estado";
	
	private static String PARAM_DET_NROLINEA ="p_nrolinea";
	private static String PARAM_DET_CODCLIENTE = "p_codcliente";
	private static String PARAM_DET_CODTIENDA = "p_codtienda";
	private static String PARAM_DET_CODPRODUCTO = "p_codproducto";
	private static String PARAM_DET_CANTIDAD = "p_cantidad";
	private static String PARAM_DET_PRECIOEW = "p_precioew";
	private static String PARAM_DET_VENTADIRECTA = "p_ventadirecta";
	private static String PARAM_DET_ESTADO = "p_estado";
	
	// Parametros de Salida
	private static String CODORDENCOMPRA = "CODOC";
	private static String PRECIOINTERNALFREIGHT = "PRECIOIF";
	private static String CODMONEDA = "CODMONEDA";
	private static String DESMONEDA = "DESMONEDA";
	private static String CODPROVEEDOR = "CODPROVEEDOR";
	private static String CODUSUARIO = "CODUSUARIO";
	private static String ORIGEN = "ORIGEN";
	private static String ESTADO = "ESTADO";
	private static String FECHAREGISTRO = "FECHAREGISTRO";
	private static String COMPONENTES = "COMPONENTES";
	
	private static String PROVEEDOR_IDENTIFICACION = "IDENTIFICACION";
	private static String PROVEEDOR_RAZONSOCIAL = "RAZONSOCIAL";
	
	private static String USUARIO_NOMBRESYAPELLIDOS = "NOMBRESYAPELLIDOS";
	
	private static String CLIENTE_NRODOCUMENTO = "NRODOCUMENTO";
	private static String CLIENTE_RAZONSOCIAL = "RAZONSOCIAL";
	
	private static String TIENDA_NOMBRE = "NOMBRE";
	
	private static String PRODUCTO_DESCRIPCION = "DESCRIPCION";
	
	private static String DET_NROLINEA ="NROLINEA";
	private static String DET_CODCLIENTE = "CODCLIENTE";
	private static String DET_CODTIENDA = "CODTIENDA";
	private static String DET_CODPRODUCTO = "CODPRODUCTO";
	private static String DET_CODPRODUCTOPROVEEDOR = "CODPRODUCTOPROVEEDOR";
	private static String DET_CANTIDAD = "CANTIDAD";
	private static String DET_CANTIDADRECIBIDA = "CANTIDADRECIBIDA";
	private static String DET_PRECIOEW = "PRECIOEW";
	private static String DET_VENTADIRECTA = "VENTADIRECTA";
	private static String DET_ESTADO = "ESTADO";
	
	private static String LISTADO = "LISTADO";
	private static String LISTADO_LINEAS = "LISTADO_LINEAS";
	
	private static String TOTAL_FILAS_AFECTADAS = "#update-count-1";
	
	private JdbcTemplate jdbcTemplate;

	@Autowired
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
	
	@Override
	public ListaOrdenCompra listarOrdenCompra(OrdenCompra ordenCompra) {
		logger.info("listarOrdenCompra");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_ORDENCOMPRA).
	    						  returningResultSet(LISTADO, new RowMapper<OrdenCompra>(){
									@Override
									public OrdenCompra mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final OrdenCompra ordenCompra = new OrdenCompra();
								        ordenCompra.setCodOC(rs.getInt(CODORDENCOMPRA));
								        ordenCompra.setPrecioInternalFreight(rs.getDouble(PRECIOINTERNALFREIGHT));
								        
								        Moneda moneda = new Moneda();
								        moneda.setCodigo(rs.getInt(CODMONEDA));
								        moneda.setDescripcion(rs.getString(DESMONEDA));
								        ordenCompra.setMoneda(moneda);
								        
								        Proveedor proveedor =  new Proveedor();
								        proveedor.setCodProveedor(rs.getInt(CODPROVEEDOR));
								        proveedor.setIdentificacion(rs.getString(PROVEEDOR_IDENTIFICACION));
								        proveedor.setRazonSocial(rs.getString(PROVEEDOR_RAZONSOCIAL));
								        ordenCompra.setProveedor(proveedor);
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        ordenCompra.setUsuario(usuario);
								        
								        ordenCompra.setOrigen(rs.getString(ORIGEN));
								        ordenCompra.setEstado(rs.getString(ESTADO));
								        ordenCompra.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return ordenCompra;
								    }
	    						  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODORDENCOMPRA, ordenCompra.getCodOC())
	    								.addValue(PARAM_CODPROVEEDOR, ordenCompra.getProveedor().getCodProveedor())
	    								.addValue(PARAM_ESTADO, ordenCompra.getEstado()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<OrdenCompra> listaOrdenCompra = (List<OrdenCompra>)data.get(LISTADO);
        
		// Instanciando objeto ListaOrdenCompra
		ListaOrdenCompra listaOrdenCompraResultado = new ListaOrdenCompra();
        // Estableciendo resultado al objeto listaOrdenCompraResultado
		listaOrdenCompraResultado.setLista(listaOrdenCompra);
        
        if (logger.isDebugEnabled() && listaOrdenCompraResultado != null)
        {
            logger.debug("size=" + listaOrdenCompraResultado.size());
        }
        return listaOrdenCompraResultado;
	}
	
	@Override
	public OrdenCompra obtenerOrdenCompra(OrdenCompra ordenCompra) {
		logger.info("obtenerOrdenCompra");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_OBTENER_ORDENCOMPRA).
	    						  returningResultSet(LISTADO, new RowMapper<OrdenCompra>(){
									@Override
									public OrdenCompra mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final OrdenCompra ordenCompra = new OrdenCompra();
								        ordenCompra.setCodOC(rs.getInt(CODORDENCOMPRA));
								        ordenCompra.setPrecioInternalFreight(rs.getDouble(PRECIOINTERNALFREIGHT));
								        
								        Moneda moneda = new Moneda();
								        moneda.setCodigo(rs.getInt(CODMONEDA));
								        ordenCompra.setMoneda(moneda);
								        
								        Proveedor proveedor =  new Proveedor();
								        proveedor.setCodProveedor(rs.getInt(CODPROVEEDOR));
								        proveedor.setIdentificacion(rs.getString(PROVEEDOR_IDENTIFICACION));
								        proveedor.setRazonSocial(rs.getString(PROVEEDOR_RAZONSOCIAL));
								        ordenCompra.setProveedor(proveedor);
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        ordenCompra.setUsuario(usuario);
								        
								        ordenCompra.setOrigen(rs.getString(ORIGEN));
								        ordenCompra.setEstado(rs.getString(ESTADO));
								        ordenCompra.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return ordenCompra;
								    }
	    						  }
								 )
								 .returningResultSet(LISTADO_LINEAS, new RowMapper<LineaOrdenCompra>(){
									@Override
									public LineaOrdenCompra mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final LineaOrdenCompra lineaOrdenCompra = new LineaOrdenCompra();
								        lineaOrdenCompra.setCodOC(rs.getInt(CODORDENCOMPRA));
								        lineaOrdenCompra.setNumeroLinea(rs.getInt(DET_NROLINEA));
								        
								        lineaOrdenCompra.setVentaDirecta(rs.getString(DET_VENTADIRECTA));
								        
								        Cliente cliente = new Cliente();
								        cliente.setCodCliente(rs.getInt(DET_CODCLIENTE));
								        cliente.setRazonSocial(rs.getString(CLIENTE_RAZONSOCIAL));
								        cliente.setNroDocumento(rs.getString(CLIENTE_NRODOCUMENTO));
								        lineaOrdenCompra.setCliente(cliente);
								        
								        Tienda tienda = new Tienda();
								        tienda.setCodigo(rs.getInt(DET_CODTIENDA));
								        tienda.setNombre(rs.getString(TIENDA_NOMBRE));
								        lineaOrdenCompra.setTienda(tienda);
								        
								        Producto producto = new Producto();
								        producto.setCodigo(rs.getInt(DET_CODPRODUCTO));
								        producto.setCodProductoProveedor(rs.getString(DET_CODPRODUCTOPROVEEDOR));
								        producto.setDescripcion(rs.getString(PRODUCTO_DESCRIPCION));
								        producto.setComponentes(rs.getString(COMPONENTES));
								        lineaOrdenCompra.setProducto(producto);
								        
								        lineaOrdenCompra.setCantidad(rs.getInt(DET_CANTIDAD));
								        lineaOrdenCompra.setCantidadRecibida(rs.getInt(DET_CANTIDADRECIBIDA));
								        lineaOrdenCompra.setCantidadRecibidaOriginalmente(lineaOrdenCompra.getCantidadRecibida());
								        lineaOrdenCompra.setPrecioExworks(rs.getDouble(DET_PRECIOEW));
								        
								        lineaOrdenCompra.setEstado(rs.getString(DET_ESTADO));
								        return lineaOrdenCompra;
								    }
	    						  });

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODORDENCOMPRA, ordenCompra.getCodOC()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
 		@SuppressWarnings("unchecked")
 		List<OrdenCompra> listaOrdenCompra= (List<OrdenCompra>)data.get(LISTADO);
         
 		// Declarando objeto orden compra Obtenido
 		OrdenCompra ordenCompraObtenido = null;
 		
 		if (logger.isDebugEnabled() && listaOrdenCompra != null)
        {
            logger.debug("size=" + listaOrdenCompra.size());
        }
 		
 		if (listaOrdenCompra != null && listaOrdenCompra.size()>0){
 			// Obteniendo el primer elemento de la lista de orden compra
 			ordenCompraObtenido = listaOrdenCompra.get(0);
 		
	        // Obteniendo lista de lineas generada de ejecutar SP
			@SuppressWarnings("unchecked")
			List<LineaOrdenCompra> listaLineaOrdenCompra= (List<LineaOrdenCompra>)data.get(LISTADO_LINEAS);
	        
			// Instanciando objeto ListaLineaOrdenCompra
			ListaLineaOrdenCompra listaLineaOrdenCompraResultado = new ListaLineaOrdenCompra();
	        // Estableciendo resultado al objeto listaLineaOrdenCompraResultado
			listaLineaOrdenCompraResultado.setLista(listaLineaOrdenCompra);
	        
			// Asignando lista de lineas al objeto ordenCompra creado
			ordenCompraObtenido.setListaLineaOrdenCompra(listaLineaOrdenCompraResultado);
			
	        if (logger.isDebugEnabled() && listaLineaOrdenCompraResultado != null)
	        {
	            logger.debug("sizeLineas=" + listaLineaOrdenCompraResultado.size());
	        }
 		}
        return ordenCompraObtenido;
	}

	@Override
	public boolean registrarOrdenCompra(OrdenCompra ordenCompra) {
		logger.info("registrarOrdenCompra");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_ORDENCOMPRA);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_PRECIOINTERNALFREIGHT, ordenCompra.getPrecioInternalFreight())
	    								.addValue(PARAM_CODMONEDA, ordenCompra.getMoneda().getCodigo())
	    								.addValue(PARAM_CODPROVEEDOR, ordenCompra.getProveedor().getCodProveedor())
	    								.addValue(PARAM_CODUSUARIO, ordenCompra.getUsuario().getCodUsuario())
	    								.addValue(PARAM_ORIGEN, ordenCompra.getOrigen())
	    								.addValue(PARAM_ESTADO, ordenCompra.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODORDENCOMPRA));

	    // Obteniendo codigo de orden compra
	    int codigoOrdenCompra = (Integer)data.get(PARAM_CODORDENCOMPRA);

	    // Estableciendo codigo de orden de compra generada
	    ordenCompra.setCodOC(codigoOrdenCompra);
	    
	    // Obteniendo lista de lineas de orden compra a agregar
	    ListaLineaOrdenCompra listaLineaOrdenCompra = ordenCompra.getListaLineaOrdenCompra();
	    
	    // Si existen lineas entonces registrarlos
	    if(listaLineaOrdenCompra.getLista() != null){
		    // Instanciando variable para llamado de SP
		    SimpleJdbcCall llamarSPLineas = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_ORDENCOMPRA);
		    
		    int i = 1;
		    for (LineaOrdenCompra item : listaLineaOrdenCompra.getLista()){
			    // Estableciendo parametros de entrada al SP
			    
		    	SqlParameterSource parametrosDetalle = new MapSqlParameterSource()
						    								.addValue(PARAM_CODORDENCOMPRA, codigoOrdenCompra)
						    								.addValue(PARAM_DET_NROLINEA, i)
						    								.addValue(PARAM_DET_CODCLIENTE, (item.getCliente()==null?null:item.getCliente().getCodCliente()))
						    								.addValue(PARAM_DET_CODTIENDA, (item.getTienda()==null?null: item.getTienda().getCodigo()))
						    								.addValue(PARAM_DET_CODPRODUCTO , item.getProducto().getCodigo())
						    								.addValue(PARAM_DET_CANTIDAD, item.getCantidad())
						    								.addValue(PARAM_DET_PRECIOEW, item.getPrecioExworks())
						    								.addValue(PARAM_DET_VENTADIRECTA, item.getVentaDirecta())
						    								.addValue(PARAM_DET_ESTADO, item.getEstado());
			    i++;
			    // Establecer parametros y ejecutar SP
			    Map<String,Object> dataDetalle = llamarSPLineas.execute(parametrosDetalle);
			    
			    // Obteniendo el total de filas afectadas al ejecutar SP
			    resultado += (Integer) dataDetalle.get(TOTAL_FILAS_AFECTADAS);
		    }
	    }
	    
	    return resultado > 0;
	}
	
	
	public int modificarOrdenCompra(OrdenCompra ordenCompra) {
		logger.info("modificarOrdenCompra");
	
		// Instanciando variable para llamado de SP
		SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
				.withProcedureName(SP_MODIFICAR_ORDENCOMPRA);

		// Estableciendo parametros de entrada al SP
		SqlParameterSource parametros = new MapSqlParameterSource()	
		.addValue(PARAM_CODORDENCOMPRA, ordenCompra.getCodOC())
		.addValue(PARAM_PRECIOINTERNALFREIGHT, ordenCompra.getPrecioInternalFreight())
		.addValue(PARAM_CODMONEDA, ordenCompra.getMoneda().getCodigo())
		.addValue(PARAM_CODPROVEEDOR, ordenCompra.getProveedor().getCodProveedor())
		.addValue(PARAM_CODUSUARIO, ordenCompra.getUsuario().getCodUsuario())
		.addValue(PARAM_ORIGEN, ordenCompra.getOrigen())
		.addValue(PARAM_ESTADO, ordenCompra.getEstado());

		// Establecer parametros y ejecutar SP
		Map<String, Object> data = llamarSP.execute(parametros);

		// Obteniendo el total de filas afectadas al ejecutar SP
		int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
		
		// -----------------------------------------------------------------------------
		return totalRegistrosAfectado;
	}
		
	public int limpiarOrdenCompraDetalle(OrdenCompra ordenCompra){
		logger.info("limpiarOrdenCompraDetalle");
        
		int resultado = 0;
		
		// Instanciando variable para llamado de SP Eliminar items registrados en transferencia pasadas
	    SimpleJdbcCall llamarSPLimpiarOrdenCompraDetalle = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LIMPIAR_DET_ORDENCOMPRA);
	    // Agregar parametro codigo de cliente
	    llamarSPLimpiarOrdenCompraDetalle.execute(new MapSqlParameterSource()
										     .addValue(PARAM_LIMCODORDENCOMPRA, ordenCompra.getCodOC()));
    		    
	    return resultado;
	}
	
	public int registrarOrdenCompraDetalle(OrdenCompra ordenCompra){
		logger.info("registrarOrdenCompraDetalle");
		
		int totalRegistrosAfectado = 0;
		
		// Obteniendo lista de lineas de la guia a agregar
	    ListaLineaOrdenCompra listaLineaOrdenCompra = ordenCompra.getListaLineaOrdenCompra();
	    
	    // Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSPLineas = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_ORDENCOMPRA);
        
	    // Obteniendo codigo de orden compra
	    int codigoOrdenCompra = ordenCompra.getCodOC();
	    
	    int i = 1;
	    for (LineaOrdenCompra item : listaLineaOrdenCompra.getLista()){
		    // Estableciendo parametros de entrada al SP
		    
	    	SqlParameterSource parametrosDetalle = new MapSqlParameterSource()
					    								.addValue(PARAM_CODORDENCOMPRA, codigoOrdenCompra)
					    								.addValue(PARAM_DET_NROLINEA, i)
					    								.addValue(PARAM_DET_CODCLIENTE, (item.getCliente()==null?null:item.getCliente().getCodCliente()))
					    								.addValue(PARAM_DET_CODTIENDA, (item.getTienda()==null?null: item.getTienda().getCodigo()))
					    								.addValue(PARAM_DET_CODPRODUCTO , item.getProducto().getCodigo())
					    								.addValue(PARAM_DET_CANTIDAD, item.getCantidad())
					    								.addValue(PARAM_DET_PRECIOEW, item.getPrecioExworks())
					    								.addValue(PARAM_DET_VENTADIRECTA, item.getVentaDirecta())
					    								.addValue(PARAM_DET_ESTADO, item.getEstado());
		    i++;

		   // Establecer parametros y ejecutar SP
		    Map<String,Object> dataDetalle = llamarSPLineas.execute(parametrosDetalle);
		    
		 // Estableciendo codgio de guia
		    item.setCodOC(ordenCompra.getCodOC());
		    
		    // Obteniendo el total de filas afectadas al ejecutar SP
		    totalRegistrosAfectado += (Integer) dataDetalle.get(TOTAL_FILAS_AFECTADAS);
		    
	    }
	    
	    return totalRegistrosAfectado;
	}
	
	
	




}
